package com.alks.yn_zs.format;

import cn.hutool.core.date.DateTime;
import com.alibaba.excel.util.StringUtils;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.entity.exception.InDataException;
import com.alks.yn_zs.data.dto.StatsDto;
import com.alks.yn_zs.data.request.StatsRequest;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author MS
 * @since 2024/11/13上午9:55
 */
public class DateFormat {

        static public final String DEF_UNIT = "日";
        static public final Integer DEF_PUSH = 0;
        static public final LocalDate DEF_END_DATE = LocalDate.now().minusDays(1);

        public static HashSet<String> getWeekDay() {
            return new HashSet<String>() {{
                add("星期一");
                add("星期二");
                add("星期三");
                add("星期四");
                add("星期五");
                add("星期六");
                add("星期日");
            }};
        }

        /**
         * 处理时间格式
         * @param type 年月日类型
         * @param date 时间
         * @return 处理后的时间
         */
        public static String formatKey(String type, LocalDate date) {
            if (date == null){
                return null;
            }
            switch (type) {
                case "当月":
                case "日":
                    return date.format(DateTimeFormatter.ofPattern("M/d"));
                case "周":
                case "本周":
                    DayOfWeek dayOfWeek = date.getDayOfWeek();
                    return dayOfWeek.getDisplayName(TextStyle.FULL, java.util.Locale.CHINA);
                case "月":
                    return date.getMonth().getValue()+"月";

                default:
                    throw new IllegalArgumentException("无效的类型: " + type);
            }
        }

        /**
         * 根据年月日推算起始日期
         * @param unit 类型
         * @param endDate 结束日期
         * @param pushUnit 前推单位
         * @return 起始日期
         */
        public static LocalDate dateStartFormat(String unit,Integer pushUnit, LocalDate endDate) {
            /*设置始末日期*/
            switch (unit) {
                case "月":
                    return endDate.minusMonths(pushUnit).withDayOfMonth(1);
                case "周":
                    return endDate.minusWeeks(pushUnit);
                case "日":
                    return endDate.minusDays(pushUnit);
                case "当月":
                    return endDate.withDayOfMonth(1);
                case "本周":
                    return endDate.with(DayOfWeek.MONDAY);
                default:
                    throw new InDataException("无效的类型: " + unit);
            }
        }

        /**
         * 补全缺少的数据
         * @param type 类型
         * @return 起始日期
         */
        public static List<String> findMissDate(String type, Set<String> keySet) {

            /*设置始末日期*/
            switch (type) {
                case "月":
                    return null;
                case "周":
                    return ArrayUtils.findMiss(keySet, DateFormat.getWeekDay());
                case "日":
                    return null;
                default:
                    throw new IllegalArgumentException("无效的类型: " + type);
            }
        }

        public static void start(StatsRequest request){
            String unit = StringUtils.isBlank(request.getTitleUnit()) ? DateFormat.DEF_UNIT : request.getTitleUnit();
            Integer pushUnit = request.getPushUnit() == null ? DateFormat.DEF_PUSH : request.getPushUnit();
            LocalDate endDate = request.getEndDate() == null ? DateFormat.DEF_END_DATE : request.getEndDate();
            LocalDate startDate = DateFormat.dateStartFormat(unit, pushUnit, endDate);

            request.setStartDate(startDate);
            request.setEndDate(endDate);
            request.setTitleUnit(unit);
            request.setPushUnit(pushUnit);
        }
    /**
     * 填充缺失的日期数据并排序
     * @param dtoList 原始数据列表
     * @param unit 时间单位类型
     * @param startDate 开始日期
     * @param endDate 结束日期
     */
    public static void fillMissingAndSort(List<StatsDto> dtoList, String unit, LocalDate startDate, LocalDate endDate, String[] types) {
        // 处理空列表情况
        if (dtoList == null) {
            return;
        }

        // 生成完整的时间序列标题
        Set<String> allTitles = new HashSet<>();
        Map<String, LocalDate> titleToDateMap = new HashMap<>();

        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            String title = DateFormat.formatKey(unit, currentDate);
            allTitles.add(title);
            if (!titleToDateMap.containsKey(title)) {
                titleToDateMap.put(title, currentDate);
            }
            currentDate = getNextDateByUnit(currentDate, unit);
        }

        // 如果列表为空，直接为所有类型和日期创建数据
        if (dtoList.isEmpty()) {
            for (String type : types) {
                for (String title : allTitles) {
                    StatsDto dto = new StatsDto();
                    dto.setType(type);
                    dto.setTitle(title);
                    dto.setCount(BigDecimal.ZERO);
                    dto.setDate(titleToDateMap.get(title));
                    dtoList.add(dto);
                }
            }

            // 排序
            dtoList.sort(Comparator
                    .comparing(StatsDto::getType)
                    .thenComparing(StatsDto::getDate, Comparator.nullsFirst(Comparator.naturalOrder()))
            );
            return;
        }

        // 按类型分组现有数据
        Map<String, Set<String>> typeTitleMap = dtoList.stream()
                .collect(Collectors.groupingBy(
                        StatsDto::getType,
                        Collectors.mapping(StatsDto::getTitle, Collectors.toSet())
                ));

        // 为每种类型补充缺失的日期数据
        Set<String> existingTypes = typeTitleMap.keySet();
        for (String type : types) {
            Set<String> existingTitles = existingTypes.contains(type) ? typeTitleMap.get(type) : new HashSet<>();
            allTitles.stream()
                    .filter(title -> !existingTitles.contains(title))
                    .forEach(missingTitle -> {
                        StatsDto missingDto = new StatsDto();
                        missingDto.setType(type);
                        missingDto.setTitle(missingTitle);
                        missingDto.setCount(BigDecimal.ZERO);
                        missingDto.setDate(titleToDateMap.get(missingTitle));
                        dtoList.add(missingDto);
                    });
        }

        // 排序：先按类型，再按日期
        dtoList.sort(Comparator
                .comparing(StatsDto::getType)
                .thenComparing(StatsDto::getDate, Comparator.nullsFirst(Comparator.naturalOrder()))
        );
    }

    /**
     * 根据单位类型获取下一个日期
     * @param date 当前日期
     * @param unit 单位类型
     * @return 下一个日期
     */
    private static LocalDate getNextDateByUnit(LocalDate date, String unit) {
        switch (unit) {
            case "日":
            case "当月":
            case "周":
            case "本周":
                return date.plusDays(1);
            case "月":
                return date.plusMonths(1);
            default:
                return date.plusDays(1);
        }
    }

}
